import logging
import numpy as np

from util.util_log import setup_logging
from util.util_csv import save_to_csv
from util.util_image import save_images_3x2, plot_images_3x1

from multi_beam_trace.util_create_trace import create_scan_traces_theta, \
    create_scan_traces_phi, create_scan_traces_theta_phi
from multi_beam_trace.util_phase_pattern import traces_2_phaseBits, phaseBits_2_patterns
from multi_beam_trace.util_analysis import get_phase_neighbor_diff, get_antenna_indicators_normalized, compare_arrays



# 配置日志，默认打印到控制台，也可以设置打印到文件
setup_logging()
# setup_logging(log_file="../../files/logs/multi-beam-trace-RAND.log")
# 获取日志记录器并记录日志
logger = logging.getLogger("[multi-beam-trace-RAND]")


# 生成一个类型为np.array()的二维数组，每个元素随机为True或者False，但是要求True和False元素的数量是相等的
def generate_balanced_boolean_array(rows, cols):
    # 计算总元素数量
    total_elements = rows * cols
    # 确保总元素数量是偶数
    if total_elements % 2 != 0:
        raise ValueError("The total number of elements must be even to have an equal number of True and False values.")
    # 计算 True 和 False 元素的数量
    num_true = total_elements // 2
    num_false = total_elements - num_true
    # 生成指定数量的 True 和 False 元素
    true_elements = [True] * num_true
    false_elements = [False] * num_false
    # 合并 True 和 False 元素
    combined_elements = true_elements + false_elements
    # 打乱这些元素
    np.random.shuffle(combined_elements)
    # 将这些元素重新塑形为二维数组
    balanced_array = np.array(combined_elements).reshape(rows, cols)
    return balanced_array


# 将balanced_array中True的值替换为phaseBit1，将balanced_array中False的值替换为phaseBit2
def replace_with_balanced_array(balanced_array, phaseBit1, phaseBit2):
    # 确保 balanced_array、phaseBit1 和 phaseBit2 的形状相同
    assert balanced_array.shape == phaseBit1.shape == phaseBit2.shape, "All arrays must have the same shape"
    # 创建一个新的数组，用于存储结果
    result = np.zeros_like(phaseBit1)
    # 使用布尔索引进行替换
    result[balanced_array] = phaseBit1[balanced_array]
    result[~balanced_array] = phaseBit2[~balanced_array]
    return result


# ============================================== 主方法 =================================================
# RAND: 随机选择一半阵元更新
def beam_1_rand(phaseBits):
    phaseBit_RAND_list = []
    for i in range(len(phaseBits)):
        if i == 0:
            phaseBit_RAND_list.append(phaseBits[i])
            continue
        phaseBit_before = phaseBit_RAND_list[i-1]
        phaseBit_now = phaseBits[i]
        # 生成一个phaseBit_rand, 随机取一半phaseBit_before和一半phaseBit_now的元素组成
        rows, cols = phaseBit_now.shape
        balanced_array = generate_balanced_boolean_array(rows, cols)
        phaseBit_RAND = replace_with_balanced_array(balanced_array, phaseBit_before, phaseBit_now)
        phaseBit_RAND_list.append(phaseBit_RAND)
    return phaseBit_RAND_list


# 单波束: 主方法
def main_beam1_rand(bit_num, traces, path_pre, result_file_name):
    # 计算码阵
    phaseBits = traces_2_phaseBits(traces, bit_num)
    # NN
    phaseBits_NN = beam_1_rand(phaseBits)
    # 码阵计算方向图
    patterns = phaseBits_2_patterns(phaseBits, bit_num)
    patterns_NN = phaseBits_2_patterns(phaseBits_NN, bit_num)
    # 计算各种评价指标
    # 1.计算 patterns, pattern_NN 的 PSLL
    pg_list_list, psll_list, psll_coor_list = get_antenna_indicators_normalized(1, patterns)
    pg_list_NN_list, psll_NN_list, psll_coor_NN_list = get_antenna_indicators_normalized(1, patterns_NN)
    # 2.todo 计算 phaseBits_NN 实际指向
    # 3.计算与前一个位置相比改变的码阵数量和
    phaseBit_diff_list, phaseBit_diff_count_list, phaseBit_diff_count_percent_list \
        = get_phase_neighbor_diff(phaseBits)
    phaseBit_diff_list_NN, phaseBit_diff_count_list_NN, phaseBit_diff_count_percent_list_NN \
        = get_phase_neighbor_diff(phaseBits_NN)
    # 保存指标
    for i in range(len(traces)):
        result_csv = {
            "(theta,phi)": traces[i],
            "pg_list": pg_list_list[i],
            "pg_list_NN": pg_list_NN_list[i],
            "psll": psll_list[i],
            "psll_NN": psll_NN_list[i],
            "psll_coor": psll_coor_list[i],
            "psll_coor_NN": psll_coor_NN_list[i],
            "phase_count_diff": phaseBit_diff_count_list[i],
            "phase_count_diff_NN": phaseBit_diff_count_list_NN[i],
            "phase_count_percent_diff": phaseBit_diff_count_percent_list[i],
            "phase_count_percent_diff_NN": phaseBit_diff_count_percent_list_NN[i]
        }
        save_to_csv([result_csv], path_pre + result_file_name)
    # 保存每个指向的图片
    path_img_pre = path_pre + "phase_pattern_diff/"
    for i in range(len(phaseBits)):
        pattern = patterns[i]
        pattern_NN = patterns_NN[i]
        phaseBit = phaseBits[i]
        phaseBit_NN = phaseBits_NN[i]
        if i == 0:
            phaseBit_NN_before = phaseBit_NN
        else:
            phaseBit_NN_before = phaseBits_NN[i-1]
        diff_phaseBit = compare_arrays(phaseBit_NN_before, phaseBit_NN)
        # 画图
        path_img = path_img_pre + str(i) + ".jpg"
        img_text = "(theta,phi)="+str(traces[i]) \
                   + ", count-diff=" + str(phaseBit_diff_count_list[i]) \
                   + "(" + str(phaseBit_diff_count_percent_list[i]) + ")" \
                   + ", count-diff(NN)=" + str(phaseBit_diff_count_list_NN[i]) \
                   + "(" + str(phaseBit_diff_count_percent_list_NN[i]) + ")"
        save_images_3x2(path_img,
                        phaseBit, f"phaseBit(t)", phaseBit_NN_before, f"phaseBit-NN(t-1)", phaseBit_NN,
                        f"phaseBit-NN(t)",
                        pattern, f"pattern", diff_phaseBit, f"diff(phaseBit(t), phaseBit-NN(t))", pattern_NN,
                        f"pattern-NN",
                        img_text)


# 主方法: 多波束动态波束扫描
def main_multi_beam_trace_rand():
    path_pre = f"../files/multi-beam-trace/beam1/RAND/"
    # 计算轨迹角度
    traces = create_scan_traces_theta(0, 90, 0)
    # traces = [[0, 90], [30, 90], [45, 90], [60, 90]]
    case_name = "theta(0,1,90)-phi(0,0,0)"
    # 主方法: 多波束动态波束扫描
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_theta(0, 90, 90)
    case_name = "theta(0,1,90)-phi(90,0,90)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_theta(0, 90, 180)
    case_name = "theta(0,1,90)-phi(180,0,180)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_theta(0, 90, 270)
    case_name = "theta(0,1,90)-phi(270,0,270)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    #
    traces = create_scan_traces_phi(10, 0, 360)
    case_name = "theta(10,0,10)-phi(0,1,360)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_phi(30, 0, 360)
    case_name = "theta(30,0,30)-phi(0,1,360)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_phi(45, 0, 360)
    case_name = "theta(45,0,45)-phi(0,1,360)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_phi(60, 0, 360)
    case_name = "theta(60,0,60)-phi(0,1,360)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    #
    traces = create_scan_traces_theta_phi(10, 10, 60)
    case_name = "theta(10,1,70)-phi(10,1,70)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_theta_phi(10, 90, 60)
    case_name = "theta(10,1,70)-phi(90,1,150)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")
    #
    traces = create_scan_traces_theta_phi(10, 180, 60)
    case_name = "theta(10,1,70)-phi(180,1,240)"
    main_beam1_rand(1, traces, path_pre + case_name + "/", case_name + ".csv")


# ====================================================== 测试方法 ===================================================
def test_merge_phases_random():
    rows, cols = 64, 64
    array1 = np.full((rows, cols), 1, dtype=int)
    array2 = np.full((rows, cols), 2, dtype=int)
    balanced_array = generate_balanced_boolean_array(rows, cols)
    result = replace_with_balanced_array(balanced_array, array1, array2)
    print("array1:")
    print(array1)
    print("\narray2:")
    print(array2)
    print("\nbalanced_array:")
    print(balanced_array)
    print("\nresult:")
    print(result)
    plot_images_3x1(array1, array2, result)



if __name__ == '__main__':
    logger.info("multi-beam-trace-RAND: random method")
    # 主函数
    main_multi_beam_trace_rand()
    # 测试函数
    # test_merge_phases_random()